using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using KiloWatt.Base.Graphics;
using KiloWatt.Base.Animation;

namespace Game1
{
    public abstract class PhisicalAnimated : PhysicObject
    {
        ModelDraw loadedModel;             //  loaded geometry
        BoundingSphere modelSize;          //  calculated size of the model
        AnimationSet animations;           //  the animations I have to choose from
        AnimationInstance[] instances;     //  the animation data, as loaded
        IBlendedAnimation[] blended;       //  state about the different animations (that can change)
        AnimationBlender blender;          //  object that blends between playing animations
        int curAnimationInstance;          //  which animation is playing? (-1 for none)
        // DebugLines debugLines;
        

        public PhisicalAnimated(String modelname, Camera camera): base(Base.Singleton)
        {
            // debugLines = new DebugLines(Base.getGraphicsDevice().GraphicsDevice);
            this.camera = camera;

            //  clear current state
            curAnimationInstance = -1;
            instances = null;
            blended = null;

            String modelpath;
            modelpath = "Models\\" + modelname;
            model = Base.Content.Load<Model>(modelpath);
            loadedModel = new ModelDraw(model, System.IO.Path.GetFileName(modelpath));
            blender = new AnimationBlender(loadedModel.Model, loadedModel.Name);
            modelSize = loadedModel.BoundingSphere;
            //  get the list of animations from our dictionary
            Dictionary<string, object> tag = loadedModel.Model.Tag as Dictionary<string, object>;
            object aobj = null;
            if (tag != null)
                tag.TryGetValue("AnimationSet", out aobj);
            animations = aobj as AnimationSet;

            //  set up animations
            if (animations != null)
            {
                instances = new AnimationInstance[animations.NumAnimations];
                //  I'll need a BlendedAnimation per animation, so that I can let the 
                //  blender object transition between them.
                blended = new IBlendedAnimation[instances.Length];
                int ix = 0;
                foreach (Animation a in animations.Animations)
                {
                    instances[ix] = new AnimationInstance(a);
                    blended[ix] = AnimationBlender.CreateBlendedAnimation(instances[ix]);
                    ++ix;
                }
            }
        }

        public override void Update(GameTime gameTime)
        {
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (dt > 0.1f) dt = 0.1f;
          // LoadModel(System.IO.Path.Combine(CurPath, CurEntryName));
            blender.Advance(dt);
        }

        public override void Draw(GameTime gameTime)
        {

            if (loadedModel != null)
            {
                //  the drawdetails set-up can be re-used for all items in the scene
                initWorldTransform();
                DrawDetails dd = new DrawDetails();

                dd.dev = Base.getGraphicsDevice().GraphicsDevice;

                dd.fogColor = new Vector4(0.5f, 0.5f, 0.5f, 1);
                dd.fogDistance = 10000;
                dd.lightAmbient = new Vector4(0.2f, 0.2f, 0.2f, 1.0f);
                dd.lightDiffuse = new Vector4(0.8f, 0.8f, 0.8f, 0);
                dd.lightDir = Vector3.Normalize(new Vector3(1, 3, 2));

                dd.viewInv = Matrix.Invert(camera.View);
                dd.viewProj = camera.View * camera.Projection;

                foreach (ModelMesh mesh in model.Meshes)
                {
                    dd.world = getWorldTransform(mesh);
                 }
                //  draw the loaded model (the only model I have)
                loadedModel.Draw(dd, blender);
            }
            //  when everything else is drawn, Z sort and draw the transparent parts
            ModelDraw.DrawDeferred();
            //base.Draw(gameTime);
            //debugLines.Draw(camera.View, camera.Projection);
            //debugLines.Reset();
        }

        public void setCurAnimation(int i, float dt)
        {
            if (instances != null && curAnimationInstance < instances.Length - 1)
                curAnimationInstance = i;
            if (curAnimationInstance > 0)
                instances[curAnimationInstance].Time = instances[curAnimationInstance - 1].Time;
            blender.TransitionAnimations(GetBlended(curAnimationInstance - 1), GetBlended(curAnimationInstance), 1.0f);
            if (blender != null)
                blender.Advance(dt);
        }

        IBlendedAnimation GetBlended(int ix)
        {
            unchecked
            {
                return (ix < 0) ? null : (ix >= blended.Length) ? null : blended[ix];
            }
        }

        protected void previousAnimation()
        {
            if (curAnimationInstance > 0)
            {
                curAnimationInstance -= 1;
                if (curAnimationInstance > 0)
                    instances[curAnimationInstance].Time = instances[curAnimationInstance - 1].Time;
                blender.TransitionAnimations(GetBlended(curAnimationInstance+ 1), GetBlended(curAnimationInstance), 1.0f);
            }

        }

        protected void nextAnimation()
        {
            if (curAnimationInstance < instances.Length - 1)
            {
                curAnimationInstance += 1;
                if (curAnimationInstance > 0)
                    instances[curAnimationInstance].Time = instances[curAnimationInstance - 1].Time;
                blender.TransitionAnimations(GetBlended(curAnimationInstance - 1), GetBlended(curAnimationInstance), 1.0f);
            }
        }
    }
}
